package com.itlong.cloud.controller.project;

import com.itlong.cloud.POJO.DTO.operate.OperateProductTypeGetPageDTO;
import com.itlong.cloud.POJO.DTO.operate.OperateProductTypeSaveDTO;
import com.itlong.cloud.POJO.VO.MessageVO;
import com.itlong.cloud.POJO.VO.operate.OperateProductTypeDetailVO;
import com.itlong.cloud.POJO.VO.operate.OperateProductTypeVO;
import com.itlong.cloud.PlatformConstants;
import com.itlong.cloud.annotation.AuthAccessRequired;
import com.itlong.cloud.annotation.LoggerInfo;
import com.itlong.cloud.constants.LogDescConstant;
import com.itlong.cloud.enumerate.FileCatalogEnum;
import com.itlong.cloud.enumerate.PropertyEquipTypeEnum;
import com.itlong.cloud.enumerate.ecode.AppErrorCodeEnum;
import com.itlong.cloud.enumerate.ecode.BaseErrorCodeEnum;
import com.itlong.cloud.enumerate.ecode.OperateErrorCodeEnum;
import com.itlong.cloud.project.operate.IOperateProductTypeServiceClient;
import com.itlong.cloud.thrown.DataAccessException;
import com.itlong.cloud.utils.encrypt.UserTokenUtil;
import com.itlong.cloud.utils.file.PemFileUtil;
import com.itlong.cloud.utils.file.UploadFileUtil;
import com.itlong.cloud.utils.network.http.HttpProtocolUtil;
import com.itlong.cloud.utils.page.Page;
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Map;

/**
 * <desc>
 *      运营-产品型号管理控制器
 * </desc>
 *
 * @createDate 2017-10-13.
 */
@RestController
@RequestMapping("/project/productType")
@RefreshScope
public class OperateProductTypeController {
    private  static final Logger LOG = LoggerFactory.getLogger(OperateProductTypeController.class);

    @Value("${" + PlatformConstants.FILE_FTP_HOST + "}")
    public String FILE_FTP_HOST;
    @Value("${" + PlatformConstants.FILE_FTP_PORT + "}")
    public String FILE_FTP_PORT;
    @Value("${" + PlatformConstants.FILE_FTP_USERNAME + "}")
    public String FILE_FTP_USERNAME;
    @Value("${" + PlatformConstants.FILE_FTP_PASSWORD + "}")
    public String FILE_FTP_PASSWORD;
    @Value("${" + PlatformConstants.FILE_ACCESS_URL + "}")
    public String FILE_ACCESS_URL;

    //腾讯相关静态文件存放路径
    @Value("${" + PlatformConstants.TENCENT_STATIC_FILE_PATH +"}")
    public String TENCENT_STATIC_FILE_PATH;

    @Autowired
    IOperateProductTypeServiceClient iOperateProductTypeServiceClient;

    @Value("${" + PlatformConstants.OPERATE_USER_PASSWORD_KEY + "}")
    String userPasswordKey;

    /**
     * <desc>
     *      上传密钥文件
     * <desc/>
     *
     * @param stream 文件流
     * @param fileName 文件名称（不含扩展名）
     * @return 
     * @author Chunjian.G
     * @createDate 2017-10-30
     */
    private String uploadKeyFile(InputStream stream, String fileName) throws Exception{
        //1.先保存一份到本地
        ByteArrayOutputStream streamForClone = PemFileUtil.cloneInputStream(stream);
        InputStream localStream = new ByteArrayInputStream(streamForClone.toByteArray());
        try {
            PemFileUtil.savePemFileToLocal(localStream, fileName + ".pem", TENCENT_STATIC_FILE_PATH);
        }catch (Exception e){
            LOG.info("产品型号密钥文件保存到本地失败", e);
            return null;
        }finally {
            localStream.close();
        }

        //2.上传到ftp服务器
        InputStream ftpStream = new ByteArrayInputStream(streamForClone.toByteArray());
        UploadFileUtil.UploadFile uploadFileUtil = new UploadFileUtil().new UploadFile(
                FILE_FTP_HOST,
                FILE_FTP_USERNAME,
                FILE_FTP_PASSWORD,
                FILE_FTP_PORT,
                ftpStream,
                "pem",
                FILE_ACCESS_URL,
                FileCatalogEnum.SECRETKEY_FILE.getType()
        );
        Map<String, Object> resultMap = null;
        try {
            //LOG.info("正在上传密钥文件");
            resultMap = UploadFileUtil.uploadFile(uploadFileUtil);
            //LOG.info("上传完毕");
        }catch (Exception e){
            LOG.info("产品型号密钥文件保存失败", e);
            return null;
        }finally {
            ftpStream.close();
        }

        if ("true".equals(resultMap.get("returnCode").toString())){
            String fileUrl = resultMap.get("accessPath").toString();
            return fileUrl;
        }else {
            LOG.info("产品型号密钥文件保存失败");
            return null;
        }
    }





    /**
     * <desc>
     *      添加单个产品型号
     * <desc/>
     *
     * @param saveDTO 新增产品型号
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-13
     */
    @AuthAccessRequired
    @LoggerInfo(operateDesc = LogDescConstant.PRODUCT_SAVE_LOG_DESC)
    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ResponseBody
    public Object saveProductType(OperateProductTypeSaveDTO saveDTO, HttpServletRequest request){
        try {
            saveDTO= HttpProtocolUtil.parseRequestParamToDTO(OperateProductTypeSaveDTO.class,request);
            //TODO 合法性判断
            if (null == saveDTO){
                return new MessageVO(BaseErrorCodeEnum.NOT_PARAM.getErrorCode());
            }
            //设备类型
            if (!PropertyEquipTypeEnum.containsBasicEquipType(saveDTO.getDeviceKind())){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_DEV_KIND_INVALID_ERR.getErrorCode());
            }
            //型号名称
            if (StringUtils.isBlank(saveDTO.getTypeName()) || saveDTO.getTypeName().length() > 15){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_NAME_INVALID_ERR.getErrorCode());
            }
            //型号代号
            if (StringUtils.isBlank(saveDTO.getTypeCode()) || saveDTO.getTypeCode().length() > 15){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_CODE_INVALID_ERR.getErrorCode());
            }
            //描述
            if (null != saveDTO.getRemark() && saveDTO.getRemark().length() > 50){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_REMARK_TOO_LONG_ERR.getErrorCode());
            }
            //云电梯产品检测是否存在
            if(PropertyEquipTypeEnum.CLOUD_ELEVATOR.getType()==saveDTO.getDeviceKind() ){
               Integer result =  iOperateProductTypeServiceClient.checkCloudElevatorExist(saveDTO.getDeviceKind(),saveDTO.getTypeCode());
               if(result>0){
                   return new MessageVO(AppErrorCodeEnum.EXIST_CLOUD_ELEVATOR_PRODUCT.getErrorCode());
               }
            }
            //门禁产品检测是否存在
            if(PropertyEquipTypeEnum.CLOUD_ENTRANCE_DEVICE.getType()==saveDTO.getDeviceKind()) {
                Integer result = iOperateProductTypeServiceClient.checkCloudElevatorExist(saveDTO.getDeviceKind(), saveDTO.getTypeCode());
                if (result > 0) {
                    return new MessageVO(AppErrorCodeEnum.EXIST_CLOUD_ENTRANCE_PRODUCT.getErrorCode());
                }
            }
            //云群控器产品检测是否存在
            if(PropertyEquipTypeEnum.CLOUD_ELEVATOR_CLUSTER_CONTROLLER.getType().equals(saveDTO.getDeviceKind())){
                Integer result =  iOperateProductTypeServiceClient.checkCloudElevatorExist(saveDTO.getDeviceKind(),saveDTO.getTypeCode());
                if(result>0){
                    return new MessageVO(AppErrorCodeEnum.EXIST_CLOUD_CONTROLLER_PRODUCT.getErrorCode());
                }
            }
            //添加云对讲型号时判断
            if (PropertyEquipTypeEnum.CLOUD_INTERCOM.getType().equals(saveDTO.getDeviceKind())){
                //型号pid合法性
                if (StringUtils.isBlank(saveDTO.getTypePid())
                        || !saveDTO.getTypePid().matches("[0-9a-zA-z]{10}")){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_PID_INVALID_ERR.getErrorCode());
                }
                //型号pid存在性
                if (iOperateProductTypeServiceClient.checkProductExist(saveDTO.getTypePid()) > 0){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_PID_EXIST_ERR.getErrorCode());
                }

                if (!ServletFileUpload.isMultipartContent(request)) {
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_KEY_FILES_EMPTY_ERR.getErrorCode());
                }
                //验证密钥文件
                //签名私钥
                if (!(saveDTO.getSignSecretKeyFile() instanceof MultipartFile)){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_SECRET_KEY_INVALID_ERR.getErrorCode());
                }
                //签名公钥
                if (!(saveDTO.getSignPubKeyFile() instanceof MultipartFile)){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_PUB_KEY_INVALID_ERR.getErrorCode());
                }
                //服务器公钥
                if (!(saveDTO.getServerKeyFile() instanceof MultipartFile)){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_SERVER_KEY_INVALID_ERR.getErrorCode());
                }

                //LOG.info("===========开始上传SignSecretKeyFile===================");
                //存儲密钥文件
                String secKeyFilePath = uploadKeyFile(((MultipartFile)saveDTO.getSignSecretKeyFile()).getInputStream(),
                        PemFileUtil.getPemFileName(saveDTO.getTypePid(), 1));
                if (null == secKeyFilePath){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_KEY_FILES_UPLOAD_ERR.getErrorCode());
                }
                saveDTO.setSignSecretKeyFile(null);
                saveDTO.setSignSecretKey(secKeyFilePath);

                //LOG.info("===========开始上传上传SignPubKeyFile==================");
                String pubKeyFilePath = uploadKeyFile(((MultipartFile)saveDTO.getSignPubKeyFile()).getInputStream(),
                        PemFileUtil.getPemFileName(saveDTO.getTypePid(), 2));
                if (null == pubKeyFilePath){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_KEY_FILES_UPLOAD_ERR.getErrorCode());
                }
                saveDTO.setSignPubKeyFile(null);
                saveDTO.setSignPubKey(pubKeyFilePath);

                //LOG.info("===========开始上传上传ServerKeyFile=====================");
                String serverKeyFilePath = uploadKeyFile(((MultipartFile)saveDTO.getServerKeyFile()).getInputStream(),
                        PemFileUtil.getPemFileName(saveDTO.getTypePid(), 3));
                if (null == serverKeyFilePath){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_KEY_FILES_UPLOAD_ERR.getErrorCode());
                }
                saveDTO.setServerKeyFile(null);
                saveDTO.setServerKey(serverKeyFilePath);
                //LOG.info("===========上传完毕======================");
            }

            Integer res = iOperateProductTypeServiceClient.saveProductType(saveDTO);
            return new MessageVO(BaseErrorCodeEnum.SUCCESS.getErrorCode(), res);
        }catch (Exception e){
            throw new DataAccessException("【运营_设备管理_添加产品型号add】添加产品型号失败", e);
        }
    }

    /**
     * <desc>
     *      更新单个产品型号
     * <desc/>
     *
     * @param updateDTO 产品型号更新信息
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-13
     */
    @AuthAccessRequired
    @LoggerInfo(operateDesc = LogDescConstant.PRODUCT_UPDATE_LOG_DESC)
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    @ResponseBody
    public Object updateProductTypes(OperateProductTypeSaveDTO updateDTO, HttpServletRequest request){
        try {
            updateDTO= HttpProtocolUtil.parseRequestParamToDTO(OperateProductTypeSaveDTO.class,request);
            //TODO 判断参数合法性
            if (null == updateDTO){
                return new MessageVO(BaseErrorCodeEnum.NOT_PARAM.getErrorCode());
            }
            //型号pid
            if (StringUtils.isBlank(updateDTO.getTypePid())){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_PID_INVALID_ERR.getErrorCode());
            }
            //设备类型
            if (!PropertyEquipTypeEnum.containsBasicEquipType(updateDTO.getDeviceKind())){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_DEV_KIND_INVALID_ERR.getErrorCode());
            }
            //型号名称
            if (StringUtils.isBlank(updateDTO.getTypeName()) || updateDTO.getTypeName().length() > 15){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_NAME_INVALID_ERR.getErrorCode());
            }
            //型号代号
            if (StringUtils.isBlank(updateDTO.getTypeCode()) || updateDTO.getTypeCode().length() > 15){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_CODE_INVALID_ERR.getErrorCode());
            }
            //描述
            if (null != updateDTO.getRemark() && updateDTO.getRemark().length() > 50){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_REMARK_TOO_LONG_ERR.getErrorCode());
            }

            //更新云对讲型号时判断
            if (PropertyEquipTypeEnum.CLOUD_INTERCOM.getType().equals(updateDTO.getDeviceKind())){
                //解密密钥
                if (!StringUtils.isBlank(updateDTO.getSignSecretKey())) {
                    updateDTO.setSignSecretKey(UserTokenUtil.getPassword(updateDTO.getSignSecretKey(),userPasswordKey));
                }
                if (!StringUtils.isBlank(updateDTO.getSignPubKey())) {
                    updateDTO.setSignPubKey(UserTokenUtil.getPassword(updateDTO.getSignPubKey(),userPasswordKey));
                }
                if (!StringUtils.isBlank(updateDTO.getServerKey())) {
                    updateDTO.setServerKey(UserTokenUtil.getPassword(updateDTO.getServerKey(),userPasswordKey));
                }
                //签名私钥
                if (StringUtils.isBlank(updateDTO.getSignSecretKey())
                        && !(updateDTO.getSignSecretKeyFile() instanceof MultipartFile)){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_SECRET_KEY_INVALID_ERR.getErrorCode());
                }else if (updateDTO.getSignSecretKeyFile() instanceof MultipartFile){
                    //先上传文件
                    String secKeyFilePath = uploadKeyFile(((MultipartFile) updateDTO.getSignSecretKeyFile()).getInputStream(),
                            PemFileUtil.getPemFileName(updateDTO.getTypePid(), 1));
                    if (null == secKeyFilePath){
                        return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_KEY_FILES_UPLOAD_ERR.getErrorCode());
                    }
                    updateDTO.setSignSecretKey(secKeyFilePath);
                    updateDTO.setSignSecretKeyFile(null);
                }
                //签名公钥
                if (StringUtils.isBlank(updateDTO.getSignPubKey())
                        && !(updateDTO.getSignPubKeyFile() instanceof MultipartFile)){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_PUB_KEY_INVALID_ERR.getErrorCode());
                }else if (updateDTO.getSignPubKeyFile() instanceof MultipartFile){
                    String pubKeyFilePath = uploadKeyFile(((MultipartFile) updateDTO.getSignPubKeyFile()).getInputStream(),
                            PemFileUtil.getPemFileName(updateDTO.getTypePid(), 2));
                    if (null == pubKeyFilePath){
                        return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_KEY_FILES_UPLOAD_ERR.getErrorCode());
                    }
                    updateDTO.setSignPubKey(pubKeyFilePath);
                    updateDTO.setSignPubKeyFile(null);
                }
                //服务器公钥
                if (StringUtils.isBlank(updateDTO.getServerKey())
                        && !(updateDTO.getServerKeyFile() instanceof MultipartFile)){
                    return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_SERVER_KEY_INVALID_ERR.getErrorCode());
                }else if (updateDTO.getServerKeyFile() instanceof MultipartFile){
                    String serverKeyFilePath = uploadKeyFile(((MultipartFile) updateDTO.getServerKeyFile()).getInputStream(),
                            PemFileUtil.getPemFileName(updateDTO.getTypePid(), 3));
                    if (null == serverKeyFilePath){
                        return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_KEY_FILES_UPLOAD_ERR.getErrorCode());
                    }
                    updateDTO.setServerKey(serverKeyFilePath);
                    updateDTO.setServerKeyFile(null);
                }
            }

            Integer result = iOperateProductTypeServiceClient.updateProductType(updateDTO);
            MessageVO messageVO = new MessageVO(updateDTO.getTypePid(), BaseErrorCodeEnum.SUCCESS.getErrorCode(), result);
            return  messageVO;
        }catch (Exception e){
            throw new DataAccessException("【运营_设备管理_更新产品型号update】更新产品型号失败", e);
        }
    }

    /**
     * <desc>
     *      删除产品型号
     * <desc/>
     *
     * @param typePid 型号ID列表
     * @param deviceKind 设备类别
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-13
     */
    @AuthAccessRequired
    @LoggerInfo(operateDesc = LogDescConstant.PRODUCT_DEL_LOG_DESC)
    @RequestMapping(value = "/del", method = RequestMethod.POST)
    @ResponseBody
    public Object removeProductType(String typePid,String deviceKind){
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            typePid = request.getAttribute("typePid") == null ? "" : request.getAttribute("typePid").toString();
            deviceKind = request.getAttribute("deviceKind") == null ? "" : request.getAttribute("deviceKind").toString();

            //判断参数合法性
            if (StringUtils.isBlank(typePid)){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_PID_INVALID_ERR.getErrorCode());
            }
            if (StringUtils.isBlank(deviceKind)){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_DEVICE_KIND_INVALID_ERR.getErrorCode());
            }
            Integer count = 0;
            if (Integer.parseInt(deviceKind) != 2) {//门禁不查询是否关联
                count = iOperateProductTypeServiceClient.getProductCount(typePid);
            }
            if (count > 0) {
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_DEVICE_IS_RELEVANCY_ERR.getErrorCode());
            }
            Integer result = iOperateProductTypeServiceClient.removeProductType(typePid);
            MessageVO messageVO = new MessageVO(typePid, BaseErrorCodeEnum.SUCCESS.getErrorCode(), result);
            return  messageVO;
        }catch (Exception e){
            throw new DataAccessException("【运营_设备管理_删除产品型号del】删除产品型号失败", e);
        }
    }

    /**
     * <desc>
     *      分页查询产品型号简易信息
     * <desc/>
     *
     * @param pageDTO 分页查询条件
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-13
     */
//    @AuthAccessRequired
    @RequestMapping(value = "/getPage", method = RequestMethod.POST)
    @ResponseBody
    public Object getPage(OperateProductTypeGetPageDTO pageDTO){
        try {
            HttpServletRequest request=((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            pageDTO= HttpProtocolUtil.parseRequestParamToDTO(OperateProductTypeGetPageDTO.class,request);
            Page<OperateProductTypeVO> page = iOperateProductTypeServiceClient.getPage(pageDTO);
            MessageVO messageVO = new MessageVO(BaseErrorCodeEnum.SUCCESS.getErrorCode(), page);
            return  messageVO;
        }catch (Exception e){
            throw new DataAccessException("【运营_设备管理_产品型号getPage】查询产品型号失败", e);
        }
    }

    /**
     * <desc>
     *      获取单个产品型号详情
     * <desc/>
     *
     * @param typePid 型号ID
     * @return
     * @author Chunjian.G
     * @createDate 2017-10-13
     */
//    @AuthAccessRequired
    @RequestMapping(value = "/getDetail", method = RequestMethod.POST)
    @ResponseBody
    public Object getDetail(String typePid){
        try {
            HttpServletRequest request=((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            typePid=request.getAttribute("typePid")==null?null:request.getAttribute("typePid").toString();
            //参数合法性
            if (StringUtils.isEmpty(typePid)){
                return new MessageVO(OperateErrorCodeEnum.PRODUCT_TYPE_PID_INVALID_ERR.getErrorCode());
            }

            OperateProductTypeDetailVO detailVO = iOperateProductTypeServiceClient.getDetail(typePid);
            //路径加密
            if (!StringUtils.isBlank(detailVO.getSignSecretKey())) {
                detailVO.setSignSecretKey(Base64.encode(detailVO.getSignSecretKey().getBytes()));
            }
            if (!StringUtils.isBlank(detailVO.getSignPubKey())) {
                detailVO.setSignPubKey(Base64.encode(detailVO.getSignPubKey().getBytes()));
            }
            if (!StringUtils.isBlank(detailVO.getServerKey())) {
                detailVO.setServerKey(Base64.encode(detailVO.getServerKey().getBytes()));
            }
            MessageVO messageVO = new MessageVO(BaseErrorCodeEnum.SUCCESS.getErrorCode(), detailVO);
            return  messageVO;
        }catch (Exception e){
            throw new DataAccessException("【运营_设备管理_产品型号getDetail】查询产品型号失败", e);
        }
    }
}
